package cn.ad.server.web.spring.service.biz;

import cn.ad.server.common.utils.monitor.MonitorHandler;
import cn.ad.server.persistence.ConfigRepository;
import cn.ad.server.web.spring.model.AdImpression;
import cn.ad.server.web.spring.model.AdNative;
import cn.ad.server.web.spring.model.Exchange;
import cn.ad.server.web.spring.model.gdt.GDTBid;
import cn.ad.server.web.spring.model.gdt.GDTImpression;
import cn.ad.server.web.spring.service.actions.context.BidContext;
import cn.ad.server.biz.internal.AdService;
import cn.ad.server.domain.ad.AdSize;
import cn.ad.server.domain.ad.AdTemplate;
import cn.ad.server.domain.ad.PlatformTagSizeMap;
import cn.ad.server.domain.ad.Strategy;
import cn.ad.server.domain.enumration.AdFormat;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.*;

@Component
public class GDTImpressionMatchService extends ImpressionMatchService<GDTBid> {

	private static Logger LOGGER = LoggerFactory.getLogger(GDTImpressionMatchService.class);

	private static Map<Integer, Boolean> unionMap = new HashMap<Integer, Boolean>();

	@Autowired
	private ConfigRepository configRepository;

	static {
		unionMap.put(79, true);
		unionMap.put(80, true);
		unionMap.put(120, true);
		unionMap.put(207, true);
		unionMap.put(208, true);
		unionMap.put(212, true);

		unionMap.put(147, true);
		unionMap.put(148, true);
		unionMap.put(149, true);
		unionMap.put(150, true);

		unionMap.put(58, true);
		unionMap.put(59, true);
		unionMap.put(70, true);
		unionMap.put(113, true);
		unionMap.put(114, true);
		unionMap.put(90, true);

		unionMap.put(10, true);
		unionMap.put(28, true);
		unionMap.put(31, true);
		unionMap.put(35, true);
		unionMap.put(69, true);
		unionMap.put(71, true);
		unionMap.put(89, true);
	}

	@Autowired
	private AdService adService;

	@Autowired
	private TrackingService trackingService;

	@Resource
	private String serverAddress;

	@Override
	public Exchange getExchange() {
		return Exchange.GDT;
	}

	@Override
	public GDTBid handler(AdImpression impression, BidContext bidContext) {
		GDTImpression gdtImpression = (GDTImpression) impression;

		Set<Strategy> strategySet = adService.fetchPlatformById(Integer.parseInt(Exchange.GDT.getValue()))
				.getStrategies();

		if (strategySet == null)
			return null;
		Set<GDTBid> matchBids = new HashSet<GDTBid>();
		
		// user dmp定向
		Set<Strategy> newStrategySet = this.matchUserDmp(bidContext, strategySet);

		if (newStrategySet == null)
			return null;

		GDTBid bid = null;

		int width = 0;
		int height = 0;

		List<Integer> creativeSpecs = gdtImpression.getCreative_specs();
		if (CollectionUtils.isEmpty(creativeSpecs))
			return null;

		bidContext.setAdxCreativeSpecs(creativeSpecs);

		for (int spec : creativeSpecs) {
			bidContext.setCreativeSpec(spec);
			AdTemplate adTemplate = adService.fetchTemplateByTagId(String.valueOf(spec));
			if (adTemplate != null) {
				bidContext.setAdFormat(AdFormat.AD_NATIVE.getValue());
				bidContext.setTemplateId(adTemplate.getId());
			} else {
				PlatformTagSizeMap ptsm = adService.fetchSizeByTagId(String.valueOf(spec));
				if (ptsm == null)
					continue;
				AdSize size = ptsm.getAdSize();
				width = size.getWidth();
				height = size.getHeight();
				bidContext.setAdFormat(ptsm.getAdFormat());
			}

			// if(spec == 65) {
			// LOGGER.info("{}",strategySet);
			// }
			bid = strategyFilter(newStrategySet, bidContext, adTemplate, gdtImpression.getNatives(), width, height,
					false, 0, null);
			if (bid != null) {
				matchBids.add(bid);
				// break;
			}
		}

		bidContext.setAdspaceWidth(String.valueOf(width));
		bidContext.setAdspaceHeight(String.valueOf(height));
		bidContext.setIncludeMimes(gdtImpression.getMultimedia_type_white_list());
		bidContext.setBidFloor(new BigDecimal(gdtImpression.getBid_floor()).divide(new BigDecimal(100)).doubleValue());
		bidContext.setImpId(gdtImpression.getId());

		if (CollectionUtils.isEmpty(matchBids))
			return null;
		List<GDTBid> bidList = new ArrayList<>(matchBids);
		Collections.sort(bidList);
		return bidList.get(0);
		
		//return new ArrayList<>(matchBids).get(new Random().nextInt(matchBids.size()));
	}
	
	
	
	
	Set<Strategy> matchUserDmp(BidContext bidContext, Set<Strategy> strategySet) {
		Set<Strategy> resultSet = new HashSet<Strategy>();
		// resultSet.addAll(strategySet);

		for (Strategy s : strategySet) {
			List<String> dmpIds = adService.fetchUserDmpId(s.getId(), Integer.valueOf(bidContext.getChannel()));
			if (CollectionUtils.isEmpty(dmpIds)) {
				resultSet.add(s);
				continue;
			}

			if (CollectionUtils.isEmpty(bidContext.getUserDmpId())) {
				// MonitorHandler.monitorStrategy(configRepository.fetchMonitoredStrategy(),
				// configRepository.fetchDebugMode(), Strategy.class.getName(),
				// String.valueOf(s.getId()),
				// "input audience_ids is null");

				// LOGGER.info("input audience_ids is null:{},{}", s.getId(),
				// bidContext.getUserDmpId());
				// resultSet.remove(s);
				continue;
			}

			Set<Integer> userDmpSet = new HashSet<Integer>();
			for (String ud : dmpIds) {
				userDmpSet.add(Integer.valueOf(ud));
			}
			Set<Integer> result = new HashSet<Integer>();
			result.addAll(userDmpSet);
			result.retainAll(new HashSet<Integer>(bidContext.getUserDmpId()));
			if (result.size() == 0) {
				// LOGGER.info("audience_ids is not match is not
				// match:{},{},{}", s.getId(), dmpIds,
				// bidContext.getUserDmpId());
				MonitorHandler.monitorStrategy(configRepository.fetchMonitoredStrategy(),
						configRepository.fetchDebugMode(), Strategy.class.getName(), String.valueOf(s.getId()),
						"audience_ids is not match");
				// resultSet.remove(s);
			} else if (result.size() > 0) {
				resultSet.add(s);
			}
		}
		return resultSet;
	}

	@Override
	public GDTBid compositeBid(BidContext bidContext, Entry entry) {
		GDTBid bid = new GDTBid();

		double bidAdViewRatio = adService.getRatio(bidContext.getCampaignId());
		bid.setBid_price(entry.getPrice().multiply(new BigDecimal(100 * bidAdViewRatio)).intValue());
		bid.setCreative_id(entry.getAuditId());
		String impressionParam = compositeImpUrls(bidContext, entry);
		String clickParam = compositeClickUrl(bidContext, entry);

		String clickParam_code = "";
		String impressionParam_code = "";

		try {
			// 移动联盟是base64，其他的是urlencode
			if (ckechMobileUnion(bidContext.getCreativeSpec())) {
				clickParam_code = Base64.encodeBase64String(clickParam.getBytes());
				impressionParam_code = Base64.encodeBase64String(impressionParam.getBytes());
			} else {
				clickParam_code = URLEncoder.encode(clickParam, "UTF-8");
				impressionParam_code = URLEncoder.encode(impressionParam, "UTF-8");
			}

		} catch (Exception e) {
			e.printStackTrace();
		}

		bid.setClick_param(clickParam_code);
		bid.setImpression_param(impressionParam_code);
		bid.setStrategy_priority(entry.getPriority());

		return bid;
	}

	boolean ckechMobileUnion(int spec) {
		if (unionMap.get(spec) == null)
			return false;
		return unionMap.get(spec);
	}

	@Override
	public void storeTemplateSpec(Entry entry, AdNative adNative) {

	}

	/**
	 * 组合印象数据
	 * 
	 * @param bidContext
	 * @param entry
	 * @return
	 */
	protected String compositeImpUrls(BidContext bidContext, Entry entry) {
		return trackingService.buildImpressionQueryString("2.0", NumberUtils.toInt(bidContext.getChannel(), 3), 3, 0,
				bidContext.getStrategyId(), bidContext.getCreativeId(), bidContext.getMaterialId(),
				bidContext.getGuid(), bidContext.getOs());
	}

	/**
	 * 组合点击数据
	 *
	 * @param bidContext
	 * @return
	 */
	protected String compositeClickUrl(BidContext bidContext, Entry entry) {
		String targetUrl = null;
		try {
			targetUrl = URLEncoder.encode(convertTargetUrlHandler.getConvertTarget(bidContext, entry.getTargetUrl()),
					"UTF-8");
		} catch (UnsupportedEncodingException e) {
			LOGGER.warn("targetUrl 编码失败.", e);
		}

		// 添加扩展url
		String extend = convertTargetUrlHandler.convertExtendClickUrl(bidContext);

		return trackingService.buildClickQueryString2("2.0", NumberUtils.toInt(bidContext.getChannel(), 3), 3, 0,
				bidContext.getStrategyId(), bidContext.getCreativeId(), bidContext.getMaterialId(),
				bidContext.getGuid(), targetUrl, extend, bidContext.getOs());
	}

}
